using System;
using System.Collections.Generic;
using System.Text;
using CCSDomain.OpenGL.Tools;
using System.Collections ;

using CommonTypes;
using CommonTypes.Math;

using BuildingBasicDomain;
using MVCFramework.Models;


using MVCFramework.View;


namespace MVCFramework.View.OpenGLVisitors
{
    public class OpenGLVisitor : IVisitor
    {
        public virtual void Visit(Object element)
        {
            if (element is IModelDrawable)
                VisitModel((IModelDrawable)element);
        //    if (element is BuildingBasicDomain .CartesianCoordinateSystem3D )
            //    VisitCoordinateSystem((BuildingBasicDomain.CartesianCoordinateSystem3D)element);
        }

        private void VisitCoordinateSystem(CartesianCoordinateSystem3D cartesianCoordinateSystem3D)
        {
            return;

            DrawAxis(cartesianCoordinateSystem3D);
        }

        private void DrawAxis(CartesianCoordinateSystem3D cartesianCoordinateSystem3D)
        {
            return;

             CartesianCoordinateSystem3D global = new CartesianCoordinateSystem3D(new Vector3D(0, 0, 0), new Vector3D(1, 0, 0), new Vector3D(0, 1, 0), new Vector3D(0, 0, 1));

            //double axisLen = Math.Abs(min/2);
            double axisLen = Math.Abs(1000);

            GL.PushMatrix();

            Vector3D angles, transport;
            cartesianCoordinateSystem3D.GetTransformation(global, out angles, out transport);

            GL.Translated(transport.X, transport.Y, transport.Z);
            GL.Rotated(angles.X , 1, 0, 0);
            GL.Rotated(angles.Y , 0, 1, 0);
            GL.Rotated(angles.Z , 0, 0, 1);

           // DrawAxisCube(axisLen);
            DrawAxisXYZ(axisLen);

            GL.PopMatrix();
        }

        private void DrawAxisXYZ(double axisLen)
        {
        

            GL.Color4f(200.0f / 255.0f, 200.0f / 255.0f, 200.0f / 255.0f, 0.6f);
            ///ZZ/////
            GL.Begin(GL.GL_LINES);
            GL.Vertex3d(0.0f, 0.0f, 0.0f);
            GL.Vertex3d(0.0f, 0.0f, axisLen / 2.0f);
            GL.End();

            GL.PushMatrix();
            GL.RasterPos3d(0, 0, axisLen / 2.0f);
            GLExtended.PrintText("Z");
            GL.PopMatrix();

            ///YY/////
            GL.Begin(GL.GL_LINES);
            GL.Vertex3d(0.0f, 0.0f, 0.0f);
            GL.Vertex3d(0.0f, axisLen / 2.0f, 0.0f);
            GL.End();

            GL.PushMatrix();
            GL.RasterPos3d(0, axisLen / 2.0f, 0);
            GLExtended.PrintText("Y");
            GL.PopMatrix();


            ///XX/////
            GL.Begin(GL.GL_LINES);
            GL.Vertex3d(0.0f, 0.0f, 0.0f);
            GL.Vertex3d(axisLen / 2.0f, 0.0f, 0.0f);
            GL.End();

            GL.PushMatrix();
            GL.RasterPos3d(axisLen / 2.0f, 0, 0);
            GLExtended.PrintText("X");
            GL.PopMatrix();

            ///zz Cone//
            IntPtr qobj = GLU.NewQuadric();
            GL.PushMatrix();
            GL.Translated(0, 0, axisLen / 2);
            GL.Rotated(180, 1.0, 0.0, 0.0);
            GLU.QuadricOrientation(qobj, GLU.INSIDE);
            GLU.QuadricNormals(qobj, GLU.SMOOTH);
            GLU.QuadricDrawStyle(qobj, GLU.FILL);
            GLU.Cylinder(qobj, 0.0f, axisLen / 30, axisLen / 10, 15, 3);
            GL.PopMatrix();


            ///YY Cone//
            IntPtr qobj1 = GLU.NewQuadric();
            GL.PushMatrix();
            GL.Translated(0, axisLen / 2, 0);
            GL.Rotated(90, 1.0, 0.0, 0.0);
            GLU.QuadricOrientation(qobj1, GLU.INSIDE);
            GLU.QuadricNormals(qobj1, GLU.SMOOTH);
            GLU.QuadricDrawStyle(qobj1, GLU.FILL);
            GLU.Cylinder(qobj1, 0.0f, axisLen / 30, axisLen / 10, 15, 3);
            GL.PopMatrix();



            ///XX Cone//
            IntPtr qobj2 = GLU.NewQuadric();
            GL.PushMatrix();
            GL.Translated(axisLen / 2, 0, 0);
            GL.Rotated(-90, 0.0, 1.0, 0.0);
            GLU.QuadricOrientation(qobj2, GLU.INSIDE);
            GLU.QuadricNormals(qobj2, GLU.SMOOTH);
            GLU.QuadricDrawStyle(qobj2, GLU.FILL);
            GLU.Cylinder(qobj2, 0.0f, axisLen / 30, axisLen / 10, 15, 3);
            GL.PopMatrix();

            GLU.DeleteQuadric(qobj2);
            GLU.DeleteQuadric(qobj1);
            GLU.DeleteQuadric(qobj);

        }

        private void DrawAxisCube(double axisLen)
        {

            GL.Color4f(200.0f / 255.0f, 200.0f / 255.0f, 200.0f / 255.0f, 0.6f);
            double cubeLen = 0.05f * axisLen;

            //ZZ
            GL.Normal3f(0, 0, 1);
            GL.Begin(GL.GL_POLYGON);
            GL.Vertex3d(0, 0, 0);
            GL.Vertex3d(0, cubeLen, 0);
            GL.Vertex3d(0, cubeLen, cubeLen);
            GL.Vertex3d(0, 0, cubeLen);
            GL.Vertex3d(0, 0, 0);
            GL.End();

            //ZZ
            GL.Normal3f(0, 0, -1);
            GL.Begin(GL.GL_POLYGON);
            GL.Vertex3d(cubeLen, 0, 0);
            GL.Vertex3d(cubeLen, 0, cubeLen);
            GL.Vertex3d(cubeLen, cubeLen, cubeLen);
            GL.Vertex3d(cubeLen, cubeLen, 0);
            GL.Vertex3d(cubeLen, 0, 0);
            GL.End();

            //XX
            GL.Normal3f(-1, 0, 0);
            GL.Begin(GL.GL_POLYGON);
            GL.Vertex3d(0, 0, 0);
            GL.Vertex3d(cubeLen, 0, 0);
            GL.Vertex3d(cubeLen, cubeLen, 0);
            GL.Vertex3d(0, cubeLen, 0);
            GL.Vertex3d(0, 0, 0);
            GL.End();

            GL.Normal3f(1, 0, 0);
            GL.Begin(GL.GL_POLYGON);
            GL.Vertex3d(0, 0, cubeLen);
            GL.Vertex3d(0, cubeLen, cubeLen);
            GL.Vertex3d(cubeLen, cubeLen, cubeLen);
            GL.Vertex3d(cubeLen, 0, cubeLen);
            GL.Vertex3d(0, 0, cubeLen);
            GL.End();

            //yy
            GL.Normal3f(0, -1, 0);

            GL.Begin(GL.GL_POLYGON);
            GL.Vertex3d(0, 0, 0);
            GL.Vertex3d(0, 0, cubeLen);
            GL.Vertex3d(cubeLen, 0, cubeLen);
            GL.Vertex3d(cubeLen, 0, 0);
            GL.Vertex3d(0, 0, 0);
            GL.End();

            GL.Normal3f(0, 1, 0);
            GL.Begin(GL.GL_POLYGON);
            GL.Vertex3d(0, cubeLen, 0);
            GL.Vertex3d(cubeLen, cubeLen, 0);
            GL.Vertex3d(cubeLen, cubeLen, cubeLen);
            GL.Vertex3d(0, cubeLen, cubeLen);
            GL.Vertex3d(0, cubeLen, 0);
            GL.End();

        }


        private static void DrawVector(double axisLen, CommonTypes.Math.Vector3D center, CommonTypes.Math.Vector3D verice)
        {
            return;

            verice = verice * axisLen;
            ///ZZ/////
            GL.Begin(GL.GL_LINES);
            GL.Vertex3d(center.X, center.Y, center.Z);
            GL.Vertex3d(verice.X , verice .Y ,verice .Z );
            GL.End();

            GL.PushMatrix();
            GL.RasterPos3d(0, 0, axisLen / 2.0f);
            GLExtended.PrintText("Z");
            GL.PopMatrix();

            ///zz Cone//
            IntPtr qobj = GLU.NewQuadric();
            GL.PushMatrix();
            GL.Translated(verice.X, verice.Y, verice.Z);

            double angle = 0;//CommonTypes .Math .Vector3D .CrossProduct(
            double degrees = CommonTypes.Geometry.RadToDeg(angle);
            verice.Normalize();
            GL.Rotated(degrees, verice.X, verice.Y, verice.Z);
            GLU.QuadricOrientation(qobj, GLU.INSIDE);
            GLU.QuadricNormals(qobj, GLU.SMOOTH);
            GLU.QuadricDrawStyle(qobj, GLU.FILL);
            GLU.Cylinder(qobj, 0.0f, axisLen / 30, axisLen / 10, 15, 3);
            GL.PopMatrix();

        }

        public void VisitModel(IModelDrawable model) // move this 
        {
            //CartesianCoordinateSystem3D system1 = new CartesianCoordinateSystem3D(new Vector3D(0, 0, 0), new Vector3D(1, 0, 0), new Vector3D(0, 1, 0), new Vector3D(0, 0, 1));
          //  system1.RotateToItsCenter(new Vector3D(90, 0, 0));

          //  this.Visit(system1);
//
            ModelContextObject ModelCO;

            if (((IModelDrawable)model).HashTable == null)
            {
                ((IModelDrawable)model).HashTable = new Hashtable();
                ((IModelDrawable)model).NeedsUpdate = true;
            }

            if (!((IModel)model).HashTable.Contains(this.ToString()))
            {
                ModelCO = new ModelContextObject();
                ((IModelDrawable)model).HashTable.Add(this.ToString(), ModelCO);
            }

            ModelCO = (ModelContextObject)((IModelDrawable)model).HashTable[this.ToString()];

            //((IModelDrawable)model).NeedsUpdate = true;

            if (((IModelDrawable)model).NeedsUpdate)
            {
                ModelCO.SetUpScene(model, this);
              //  ((IModelDrawable)model).NeedsUpdate = false;
            }
         //   return;

            //GL.PushMatrix();
             //  GL.CallList(ModelCO.listname);
            // GL.PopMatrix();
       
            IList<ILine> elasticlines = null ;

            if (model is IModel)
                elasticlines = ((IModel)model).GetObject<List<ILine>>(ModelData.ElasticLines);

            if (elasticlines != null)
                foreach (ILine line in elasticlines)
                    Visit(line);

        }

    }
}